package com.yznote.cloudesk.config;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.yznote.cloudesk.common.constants.YCacheConstant;
import com.yznote.cloudesk.common.pojo.User;
import com.yznote.cloudesk.cache.yCache.YCache;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author : xiaozhoutongxue
 * @date : 2022/10/12 22:25
 */
@Slf4j
@Data
@Component
public class JWTconfig {
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    FieldConfig fieldConfig1;
    @Autowired
    YCache yCache1;

    private static FieldConfig fieldConfig;
    private static RedisTemplate redisTemplate1;
    private static Map<String, Long> tokenMap = new HashMap();
    private static YCache yCache;

    //先构造方法 再Autowired 再postConstruct
    @PostConstruct
    public void setFiled() {
        this.fieldConfig = fieldConfig1;
        this.redisTemplate1 = redisTemplate;
        this.yCache = yCache1;
    }

    /**
     * 创建Token
     * @param userName
     * @param userId
     * @return
     */
    public static String createToken(String userName, Long userId) {
        // header Map
        Map<String, Object> headerMap = new HashMap();
        headerMap.put("alg", "HS256");
        headerMap.put("typ", "JWT");
        String token = null;
        Date dateStart = new Date();
        //Date dateEnd = new Date(System.currentTimeMillis() + 60  * 1000*60*);
        //token 有效时间无  day
        try {
            token = JWT.create()
                    .withHeader(headerMap)
                    .withClaim("userName", userName)
                    .withClaim("userId", userId)
                    .withIssuer("yyds")
                    .withClaim("createTime", dateStart.getTime())
                    //.withExpiresAt(dateEnd)
                    .sign(Algorithm.HMAC256(fieldConfig.getSECRET()));
            log.info("token:" + token);
        } catch (JWTCreationException | UnsupportedEncodingException exception) {
            return "create token fail";
        } catch (Exception e) {
            return "create token fail";
        }
        yCache.put(YCacheConstant.TOKEN,userId.toString(), dateStart.getTime(),20, TimeUnit.MINUTES);
        return token;
    }

    /**
     * @param token
     * @return
     */
    public static Map<String, Claim> verifyTokenUtil(String token) {
        DecodedJWT jwt = null;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256("YYDS")).build();
            jwt = verifier.verify(token);
        } catch (TokenExpiredException e) {
            log.info(e.toString());
            return null;
            // token 超时
        } catch (Exception e) {
            // token 校验失败, 抛出Token验证非法异常,返回null
            log.info("token错误");
            return null;
        }
        return jwt.getClaims();
    }

    /**
     * 验证token正确性
     * @param token
     * @return
     */
    public static User verifyToken(String token) {
        Map<String, Claim> stringClaimMap = verifyTokenUtil(token);
        if ( stringClaimMap== null) {
            return null;
        }
        long startData = stringClaimMap.get("createTime").asLong();
        long userId = stringClaimMap.get("userId").asLong();
        String userName = stringClaimMap.get("userName").asString();
        //二级缓存策略
        Long t = null;
        if ((t = (Long) yCache.tryGet(YCacheConstant.TOKEN,userId+"")) != null && t == startData) {
            return new User(userName, null, userId, null,null, null, null, null,null);
        }
        return null;

    }

    public static Long getId(String token) {
        Map<String, Claim> stringClaimMap = verifyTokenUtil(token);
        return stringClaimMap.get("userId").asLong();
    }

    public static String getUserName(String token) {
        Map<String, Claim> stringClaimMap = verifyTokenUtil(token);
        return stringClaimMap.get("userName").asString();
    }


}
